﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Input;
using BotModels;
using BotTalkLibrary;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;

namespace AllBots.ViewModel
{
    public class ChatViewModel : ViewModelBase
    {
        private RequestMaker caller;

        #region INPC

        public const string ConversationPropertyName = "Conversation";
        private Conversation conversation;
        public Conversation Conversation
        {
            get { return conversation; } 
            set
            {
                if (value == conversation)
                {
                    return;
                }

                conversation = value;
                RaisePropertyChanged(ConversationPropertyName);
            }
        }

        public const string NextMessagePropertyName = "NextMessage";
        private Message nextMessage;
        public Message NextMessage
        {
            get { return nextMessage; }
            set
            {
                if (value == nextMessage)
                {
                    return;
                }

                nextMessage = value;
                RaisePropertyChanged(NextMessagePropertyName);
            }
        }

        public const string SelectedMessagePropertyName = "SelectedMessage";
        private Message selectedMessage;
        public Message SelectedMessage
        {
            get { return selectedMessage; }
            set
            {
                if (selectedMessage == value)
                {
                    return;
                }

                selectedMessage = value;
                RaisePropertyChanged(SelectedMessagePropertyName);
            }
        }

        public const string NotificationTextPropertyName = "NotificationText";
        private string notificationText = string.Empty;
        public string NotificationText
        {
            get
            {
                return notificationText;
            }

            set
            {
                if (notificationText == value)
                {
                    return;
                }

                var oldValue = notificationText;
                notificationText = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(NotificationTextPropertyName);
            }
        }

        public const string NotifyPropertyName = "Notify";
        private bool notify = false;
        public bool Notify
        {
            get
            {
                return notify;
            }

            set
            {
                if (notify == value)
                {
                    return;
                }

                var oldValue = notify;
                notify = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(NotifyPropertyName);
            }
        }

        public const string IsSendingPropertyName = "IsSending";
        private bool isSending = false;
        public bool IsSending
        {
            get
            {
                return isSending;
            }

            set
            {
                if (isSending == value)
                {
                    return;
                }

                var oldValue = isSending;
                isSending = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(IsSendingPropertyName);
                sendMessageCommand.RaiseCanExecuteChanged();
            }
        }

        #endregion(

        #region Commands

        private RelayCommand sendMessageCommand;
        public ICommand SendMessageCommand
        {
            get
            {
                if (sendMessageCommand == null)
                {
                    sendMessageCommand = new RelayCommand(SendMessage, ValidateSendMessage);
                }

                return sendMessageCommand;
            }
        }

        #endregion

        public ChatViewModel()
        {
            if (IsInDesignMode)
            {
                InitSampleData();
            }
            else
            {
                InitViewModel();
                Messenger.Default.Register<GenericMessage<Bot>>(this, botMessage =>
                {
                    RefreshViewModel(botMessage.Content);
                });
            }
        }

        #region Utility methods

        private void SendMessage()
        {
            IsSending = true;
            Message clone = NextMessage.Clone<Message>();
            Conversation.Log.Add(clone);
            caller.SendBotMessage(Conversation.Bot.Id, NextMessage.Content, conversation.Id);
        }

        private bool ValidateSendMessage()
        {
            return !string.IsNullOrEmpty(NextMessage.Content) && !isSending;
        }

        #endregion

        #region EventHandlers

        private void BotNameReceived(object sender, GetBotNameEventArgs args)
        {
            if (args.Error == null)
            {
                Conversation.Bot.Name = args.Name;
            }
            else
            {
                MessageBox.Show(args.Error);
            }
        }

        private void AnswerReceived(object sender, SendBotMessageEventArgs args)
        {
            if (args.Error == null)
            {
                // Building and adding the answer to the conversation
                Message answer = args.Message;
                answer.From = Conversation.Bot.Name;
                Conversation.Log.Add(answer);

                // Filling the conversation id if empty
                if (conversation.Id == null)
                {
                    conversation.Id = args.ConversationId;
                }

                NextMessage.Content = string.Empty;
            }
            else
            {
                MessageBox.Show(args.Error);
            }

            IsSending = false;
        }

        private void NextMessageChanged(object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName.Equals("Content"))
            {
                ((RelayCommand)SendMessageCommand).RaiseCanExecuteChanged();
            }
        }

        private void SpeakTextStatusChanged(object sender, EventArgs e)
        {
            var args = e as OpenReadCompletedEventArgs;
            if (args == null)
            {
                SelectedMessage = null;
            }
        }

        #endregion

        #region ViewModel methods

        /// <summary>
        /// Inits the view model.
        /// </summary>
        private void InitViewModel()
        {
            Conversation = new Conversation();
            NextMessage = new Message() { From = "Me" };
            NextMessage.PropertyChanged += NextMessageChanged;

            caller = new RequestMaker();
            caller.GetBotNameCompleted += BotNameReceived;
            caller.SendBotMessageCompleted += AnswerReceived;
        }

        private void RefreshViewModel(Bot bot) {
            // Clear and renew the bot conversation
            Conversation.Log.Clear();
            conversation.Bot = bot;
            conversation.Id = null;
            NextMessage.Content = string.Empty;
        }

        private void InitSampleData()
        {
            notificationText = "Hello les copains";
            Conversation = new Conversation()
            {
                Bot = new Bot() { Id = "e9a7b3a93e34c168", Name = "OzTK" },
                Log = new ObservableCollection<Message>
                                                 {
                                                     new Message() {From = "Me", Content = "Hello"},
                                                     new Message() {From = "OzTK", Content = "Hello, how are you?"},
                                                     new Message()
                                                         {
                                                             From = "Me",
                                                             Content = "Fine thank you. What's your favorite colour?"
                                                         },
                                                     new Message() {From = "OzTK", Content = "Blue"}
                                                 }
            };
        }

        /// <summary>
        /// Unregisters this instance from the Messenger class and clean VM data
        /// </summary>
        public override void Cleanup()
        {
            caller.GetBotNameCompleted -= BotNameReceived;
            caller.SendBotMessageCompleted -= AnswerReceived;
            NextMessage.PropertyChanged -= NextMessageChanged;
            Messenger.Default.Unregister(this);

            base.Cleanup();
        }

        #endregion
    }
}